home *** CD-ROM | disk | FTP | other *** search
/ Hot Super Models / Hot Super Models.iso / unix / x11 / xv200.tar / xv-2.00 / xvgif.c < prev    next >
C/C++ Source or Header  |  1992-01-02  |  17KB  |  600 lines

  1. /*
  2.  * xvgif.c  -  GIF loading code for 'xv'.  Based strongly on...
  3.  *
  4.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  5.  *
  6.  * Copyright (c) 1988, 1989 by Patrick J. Naughton
  7.  *
  8.  * Author: Patrick J. Naughton
  9.  * naughton@wind.sun.com
  10.  *
  11.  * Permission to use, copy, modify, and distribute this software and its
  12.  * documentation for any purpose and without fee is hereby granted,
  13.  * provided that the above copyright notice appear in all copies and that
  14.  * both that copyright notice and this permission notice appear in
  15.  * supporting documentation.
  16.  *
  17.  * This file is provided AS IS with no warranties of any kind.  The author
  18.  * shall have no liability with respect to the infringement of copyrights,
  19.  * trade secrets or any patents by this file or any part thereof.  In no
  20.  * event will the author be liable for any lost revenue or profits or
  21.  * other special, indirect and consequential damages.
  22.  *
  23.  */
  24.  
  25. /*
  26.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  27.  *                       The University of Pennsylvania
  28.  *
  29.  * Permission to use, copy, and distribute for non-commercial purposes,
  30.  * is hereby granted without fee, providing that the above copyright
  31.  * notice appear in all copies and that both the copyright notice and this
  32.  * permission notice appear in supporting documentation.
  33.  *
  34.  * The software may be modified for your own purposes, but modified versions
  35.  * may not be distributed.
  36.  *
  37.  * This software is provided "as is" without any expressed or implied warranty.
  38.  *
  39.  * The author may be contacted via:
  40.  *    US Mail:   John Bradley
  41.  *               GRASP Lab, Room 301C
  42.  *               3401 Walnut St.
  43.  *               Philadelphia, PA  19104
  44.  *
  45.  *    Phone:     (215) 898-8813
  46.  *    EMail:     bradley@cis.upenn.edu
  47.  */
  48.  
  49. #include "xv.h"
  50.  
  51. typedef int boolean;
  52.  
  53. #define NEXTBYTE (*ptr++)
  54. #define IMAGESEP 0x2c
  55. #define EXTENSION 0x21
  56. #define INTERLACEMASK 0x40
  57. #define COLORMAPMASK 0x80
  58.  
  59.   
  60.  
  61. FILE *fp;
  62.  
  63. int BitOffset = 0,        /* Bit Offset of next code */
  64.     XC = 0, YC = 0,        /* Output X and Y coords of current pixel */
  65.     Pass = 0,            /* Used by output routine if interlaced pic */
  66.     OutCount = 0,        /* Decompressor output 'stack count' */
  67.     RWidth, RHeight,        /* screen dimensions */
  68.     Width, Height,        /* image dimensions */
  69.     LeftOfs, TopOfs,        /* image offset */
  70.     BitsPerPixel,        /* Bits per pixel, read from GIF header */
  71.     BytesPerScanline,        /* bytes per scanline in output raster */
  72.     ColorMapSize,        /* number of colors */
  73.     Background,            /* background color */
  74.     CodeSize,            /* Code size, read from GIF header */
  75.     InitCodeSize,        /* Starting code size, used during Clear */
  76.     Code,            /* Value returned by ReadCode */
  77.     MaxCode,            /* limiting value for current code size */
  78.     ClearCode,            /* GIF clear code */
  79.     EOFCode,            /* GIF end-of-information code */
  80.     CurCode, OldCode, InCode,    /* Decompressor variables */
  81.     FirstFree,            /* First free code, generated per GIF spec */
  82.     FreeCode,            /* Decompressor,next free slot in hash table */
  83.     FinChar,            /* Decompressor variable */
  84.     BitMask,            /* AND mask for data size */
  85.     ReadMask,            /* Code AND mask for current code size */
  86.     Misc;                       /* miscellaneous bits (interlace, local cmap)*/
  87.  
  88.  
  89. boolean Interlace, HasColormap;
  90.  
  91. byte *RawGIF;            /* The heap array to hold it, raw */
  92. byte *Raster;            /* The raster data stream, unblocked */
  93.  
  94.     /* The hash table used by the decompressor */
  95. int Prefix[4096];
  96. int Suffix[4096];
  97.  
  98.     /* An output array used by the decompressor */
  99. int OutCode[1025];
  100.  
  101. int   gif89 = 0;
  102. char *id87 = "GIF87a";
  103. char *id89 = "GIF89a";
  104.  
  105. static int EGApalette[16][3] = {
  106.   {0,0,0},       {0,0,128},     {0,128,0},     {0,128,128}, 
  107.   {128,0,0},     {128,0,128},   {128,128,0},   {200,200,200},
  108.   {100,100,100}, {100,100,255}, {100,255,100}, {100,255,255},
  109.   {255,100,100}, {255,100,255}, {255,255,100}, {255,255,255} };
  110.   
  111.  
  112. static int  ReadCode();
  113. static void DoInterlace();
  114. static int  GifError();
  115.  
  116. int filesize;
  117.  
  118. /*****************************/
  119. int LoadGIF(fname,nc)
  120.   char *fname;
  121.   int   nc;
  122. /*****************************/
  123. {
  124.   register byte  ch, ch1;
  125.   register byte *ptr, *ptr1, *picptr;
  126.   register int   i;
  127.   int            npixels, maxpixels, aspect;
  128.  
  129.   /* initialize variables */
  130.   BitOffset = XC = YC = Pass = OutCount = npixels = maxpixels = 0;
  131.   RawGIF = Raster = pic = NULL;
  132.   gif89 = 0;
  133.  
  134.   fp = fopen(fname,"r");
  135.   if (!fp) {
  136.     fprintf(stderr,"%s: LoadGIF() - unable to open file '%s'\n",cmd,fname);
  137.     return 1;
  138.   }
  139.   
  140.   /* find the size of the file */
  141.   fseek(fp, 0L, 2);
  142.   filesize = ftell(fp);
  143.   fseek(fp, 0L, 0);
  144.   
  145.   /* the +256's are so we can read truncated GIF files without fear of 
  146.      segmentation violation */
  147.   if (!(ptr = RawGIF = (byte *) calloc(filesize+256,1)))
  148.     return( GifError("not enough memory to read gif file") );
  149.   
  150.   if (!(Raster = (byte *) calloc(filesize+256,1)))    
  151.     return( GifError("not enough memory to read gif file") );
  152.   
  153.   if (fread(ptr, filesize, 1, fp) != 1) 
  154.     return( GifError("GIF data read failed") );
  155.   
  156.   if      (strncmp(ptr, id87, 6)==0) gif89 = 0;
  157.   else if (strncmp(ptr, id89, 6)==0) gif89 = 1;
  158.   else    return( GifError("not a GIF file"));
  159.   
  160.   ptr += 6;
  161.   
  162.   /* Get variables from the GIF screen descriptor */
  163.   
  164.   ch = NEXTBYTE;
  165.   RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
  166.   ch = NEXTBYTE;
  167.   RHeight = ch + 0x100 * NEXTBYTE;
  168.   
  169.   ch = NEXTBYTE;
  170.   HasColormap = ((ch & COLORMAPMASK) ? True : False);
  171.   
  172.   BitsPerPixel = (ch & 7) + 1;
  173.   numcols = ColorMapSize = 1 << BitsPerPixel;
  174.   BitMask = ColorMapSize - 1;
  175.   
  176.   Background = NEXTBYTE;        /* background color... not used. */
  177.   
  178.   aspect = NEXTBYTE;
  179.   if (aspect) {
  180.     if (!gif89) return(GifError("corrupt GIF file (screen descriptor)"));
  181.     else normaspect = (float) (aspect + 15) / 64.0;   /* gif89 aspect ratio */
  182.     if (DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect);
  183.   }
  184.   
  185.   
  186.   /* Read in global colormap. */
  187.   
  188.   if (HasColormap)
  189.     for (i=0; i<ColorMapSize; i++) {
  190.       r[i] = NEXTBYTE;
  191.       g[i] = NEXTBYTE;
  192.       b[i] = NEXTBYTE;
  193.     }
  194.   else {  /* no colormap in GIF file */
  195.     /* put std EGA palette (repeated 16 times) into colormap, for lack of
  196.        anything better to do */
  197.  
  198.     for (i=0; i<256; i++) {
  199.       r[i] = EGApalette[i&15][0];
  200.       g[i] = EGApalette[i&15][1];
  201.       b[i] = EGApalette[i&15][2];
  202.     }
  203.   }
  204.  
  205.  
  206.   while ( (i=NEXTBYTE) == EXTENSION) {  /* parse extension blocks */
  207.     int i, fn, blocksize, aspnum, aspden;
  208.  
  209.     /* read extension block */
  210.     fn = NEXTBYTE;
  211.  
  212.     if (fn == 'R') {                  /* GIF87 aspect extension */
  213.       blocksize = NEXTBYTE;
  214.       if (blocksize == 2) {
  215.     aspnum = NEXTBYTE;
  216.     aspden = NEXTBYTE;
  217.     if (aspden>0 && aspnum>0) 
  218.       normaspect = (float) aspnum / (float) aspden;
  219.     else { normaspect = 1.0;  aspnum = aspden = 1; }
  220.  
  221.     if (DEBUG) fprintf(stderr,"GIF87 aspect extension: %d:%d = %f\n", 
  222.                aspnum, aspden,normaspect);
  223.       }
  224.       else {
  225.     for (i=0; i<blocksize; i++) NEXTBYTE;
  226.       }
  227.     }
  228.  
  229.     else if (fn == 0xFE) {  /* Comment Extension.  just eat it */
  230.       int ch, j, sbsize;
  231.  
  232.       /* read (and ignore) data sub-blocks */
  233.       do {
  234.     j = 0;  sbsize = NEXTBYTE;
  235.     while (j<sbsize) {
  236.       ch = NEXTBYTE;  j++;
  237.       if (DEBUG) fprintf(stderr,"%c", ch);
  238.     }
  239.       } while (sbsize);
  240.     }
  241.  
  242.     else if (fn == 0x01) {  /* PlainText Extension */
  243.       int j,sbsize,ch;
  244.       int tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight, fg, bg;
  245.       
  246.       SetISTR(ISTR_WARNING, 
  247.           "PlainText extension found in GIF file.  Ignored.");
  248.  
  249.       sbsize   = NEXTBYTE;
  250.       tgLeft   = NEXTBYTE;  tgLeft   += (NEXTBYTE)<<8;
  251.       tgTop    = NEXTBYTE;  tgTop    += (NEXTBYTE)<<8;
  252.       tgWidth  = NEXTBYTE;  tgWidth  += (NEXTBYTE)<<8;
  253.       tgHeight = NEXTBYTE;  tgHeight += (NEXTBYTE)<<8;
  254.       cWidth   = NEXTBYTE;
  255.       cHeight  = NEXTBYTE;
  256.       fg       = NEXTBYTE;
  257.       bg       = NEXTBYTE;
  258.       i=12;
  259.       for ( ; i<sbsize; i++) NEXTBYTE;   /* read rest of first subblock */
  260.       
  261.       if (DEBUG) fprintf(stderr,
  262.        "PlainText: tgrid=%d,%d %dx%d  cell=%dx%d  col=%d,%d\n",
  263.         tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight, fg, bg);
  264.  
  265.       /* read (and ignore) data sub-blocks */
  266.       do {
  267.     j = 0;
  268.     sbsize = NEXTBYTE;
  269.     while (j<sbsize) {
  270.       ch = NEXTBYTE;  j++;
  271.       if (DEBUG) fprintf(stderr,"%c", ch);
  272.     }
  273.       } while (sbsize);
  274.     }
  275.  
  276.  
  277.     else if (fn == 0xF9) {  /* Graphic Control Extension */
  278.       int j, sbsize;
  279.  
  280.       SetISTR(ISTR_WARNING, 
  281.           "Graphic Control Extension in GIF file.  Ignored.");
  282.  
  283.       /* read (and ignore) data sub-blocks */
  284.       do {
  285.     j = 0; sbsize = NEXTBYTE;
  286.     while (j<sbsize) { NEXTBYTE;  j++; }
  287.       } while (sbsize);
  288.     }
  289.  
  290.  
  291.     else { /* unknown extension */
  292.       int j, sbsize;
  293.  
  294.       SetISTR(ISTR_WARNING, 
  295.           "Unknown extension 0x%02x in GIF file.  Ignored.",fn);
  296.  
  297.       /* read (and ignore) data sub-blocks */
  298.       do {
  299.     j = 0; sbsize = NEXTBYTE;
  300.     while (j<sbsize) { NEXTBYTE;  j++; }
  301.       } while (sbsize);
  302.     }
  303.   }
  304.  
  305.  
  306.   /* Check for image seperator */
  307.   if (i != IMAGESEP) 
  308.     return( GifError("corrupt GIF file (no image separator)") );
  309.   
  310.   /* Now read in values from the image descriptor */
  311.   
  312.   ch = NEXTBYTE;
  313.   LeftOfs = ch + 0x100 * NEXTBYTE;
  314.   ch = NEXTBYTE;
  315.   TopOfs = ch + 0x100 * NEXTBYTE;
  316.   ch = NEXTBYTE;
  317.   Width = ch + 0x100 * NEXTBYTE;
  318.   ch = NEXTBYTE;
  319.   Height = ch + 0x100 * NEXTBYTE;
  320.  
  321.   Misc = NEXTBYTE;
  322.   Interlace = ((Misc & INTERLACEMASK) ? True : False);
  323.  
  324.   if (Misc & 0x80) {
  325.     for (i=0; i< 1 << ((Misc&7)+1); i++) {
  326.       r[i] = NEXTBYTE;
  327.       g[i] = NEXTBYTE;
  328.       b[i] = NEXTBYTE;
  329.     }
  330.   }
  331.  
  332.  
  333.   if (!HasColormap && !(Misc&0x80)) {
  334.     /* no global or local colormap */
  335.     SetISTR(ISTR_WARNING,
  336.         "No colormap in this GIF file.  Assuming EGA colors.");
  337.   }
  338.     
  339.  
  340.   
  341.   /* Start reading the raster data. First we get the intial code size
  342.    * and compute decompressor constant values, based on this code size.
  343.    */
  344.   
  345.   CodeSize = NEXTBYTE;
  346.   ClearCode = (1 << CodeSize);
  347.   EOFCode = ClearCode + 1;
  348.   FreeCode = FirstFree = ClearCode + 2;
  349.   
  350.   /* The GIF spec has it that the code size is the code size used to
  351.    * compute the above values is the code size given in the file, but the
  352.    * code size used in compression/decompression is the code size given in
  353.    * the file plus one. (thus the ++).
  354.    */
  355.   
  356.   CodeSize++;
  357.   InitCodeSize = CodeSize;
  358.   MaxCode = (1 << CodeSize);
  359.   ReadMask = MaxCode - 1;
  360.   
  361.  
  362.  
  363.   /* UNBLOCK:
  364.    * Read the raster data.  Here we just transpose it from the GIF array
  365.    * to the Raster array, turning it from a series of blocks into one long
  366.    * data stream, which makes life much easier for ReadCode().
  367.    */
  368.   
  369.   ptr1 = Raster;
  370.   do {
  371.     ch = ch1 = NEXTBYTE;
  372.     while (ch--) { *ptr1 = NEXTBYTE; ptr1++; }
  373.     if ((ptr - RawGIF) > filesize) {
  374.       SetISTR(ISTR_WARNING,
  375.           "This GIF file seems to be truncated.  Winging it.");
  376.       break;
  377.     }
  378.   } while(ch1);
  379.   free(RawGIF);     RawGIF = NULL;     /* We're done with the raw data now */
  380.  
  381.  
  382.  
  383.   if (DEBUG) {
  384.     fprintf(stderr,"xv: LoadGIF() - picture is %dx%d, %d bits, %sinterlaced\n",
  385.         Width, Height, BitsPerPixel, Interlace ? "" : "non-");
  386.   }
  387.   
  388.   SetISTR(ISTR_FORMAT, "GIF%s, %d bits per pixel, %sinterlaced.  (%d bytes)",
  389.       (gif89) ? "89" : "87", BitsPerPixel, 
  390.       Interlace ? "" : "non-", filesize);
  391.  
  392.  
  393.  
  394.   /* Allocate the 'pic' */
  395.   pWIDE = Width;  pHIGH = Height;
  396.   maxpixels = Width*Height;
  397.   picptr = pic = (byte *) malloc(maxpixels);
  398.   sprintf(formatStr, "%dx%d GIF%s.", pWIDE, pHIGH, (gif89) ? "89" : "87");
  399.  
  400.   if (!pic) 
  401.     return( GifError("not enough memory for 'pic'") );
  402.  
  403.   
  404.   /* Decompress the file, continuing until you see the GIF EOF code.
  405.    * One obvious enhancement is to add checking for corrupt files here.
  406.    */
  407.   
  408.   Code = ReadCode();
  409.   while (Code != EOFCode) {
  410.     /* Clear code sets everything back to its initial value, then reads the
  411.      * immediately subsequent code as uncompressed data.
  412.      */
  413.  
  414.     if (Code == ClearCode) {
  415.       CodeSize = InitCodeSize;
  416.       MaxCode = (1 << CodeSize);
  417.       ReadMask = MaxCode - 1;
  418.       FreeCode = FirstFree;
  419.       Code = ReadCode();
  420.       CurCode = OldCode = Code;
  421.       FinChar = CurCode & BitMask;
  422.       if (!Interlace) *picptr++ = FinChar;
  423.          else DoInterlace(FinChar);
  424.       npixels++;
  425.     }
  426.     else {
  427.       /* If not a clear code, must be data: save same as CurCode and InCode */
  428.  
  429.       /* if we're at maxcode and didn't get a clear, stop loading */
  430.       if (FreeCode>=4096) { /* printf("freecode blew up\n"); */
  431.                 break; }
  432.  
  433.       CurCode = InCode = Code;
  434.       
  435.       /* If greater or equal to FreeCode, not in the hash table yet;
  436.        * repeat the last character decoded
  437.        */
  438.       
  439.       if (CurCode >= FreeCode) {
  440.     CurCode = OldCode;
  441.     if (OutCount > 1024) {  /* printf("outcount1 blew up\n"); */ break; }
  442.     OutCode[OutCount++] = FinChar;
  443.       }
  444.       
  445.       /* Unless this code is raw data, pursue the chain pointed to by CurCode
  446.        * through the hash table to its end; each code in the chain puts its
  447.        * associated output code on the output queue.
  448.        */
  449.       
  450.       while (CurCode > BitMask) {
  451.     if (OutCount > 1024) break;   /* corrupt file */
  452.     OutCode[OutCount++] = Suffix[CurCode];
  453.     CurCode = Prefix[CurCode];
  454.       }
  455.       
  456.       if (OutCount > 1024) { /* printf("outcount blew up\n"); */ break; }
  457.       
  458.       /* The last code in the chain is treated as raw data. */
  459.       
  460.       FinChar = CurCode & BitMask;
  461.       OutCode[OutCount++] = FinChar;
  462.       
  463.       /* Now we put the data out to the Output routine.
  464.        * It's been stacked LIFO, so deal with it that way...
  465.        */
  466.  
  467.       /* safety thing:  prevent exceeding range of 'pic' */
  468.       if (npixels + OutCount > maxpixels) OutCount = maxpixels-npixels;
  469.     
  470.       npixels += OutCount;
  471.       if (!Interlace) for (i=OutCount-1; i>=0; i--) *picptr++ = OutCode[i];
  472.                 else  for (i=OutCount-1; i>=0; i--) DoInterlace(OutCode[i]);
  473.       OutCount = 0;
  474.  
  475.       /* Build the hash table on-the-fly. No table is stored in the file. */
  476.       
  477.       Prefix[FreeCode] = OldCode;
  478.       Suffix[FreeCode] = FinChar;
  479.       OldCode = InCode;
  480.       
  481.       /* Point to the next slot in the table.  If we exceed the current
  482.        * MaxCode value, increment the code size unless it's already 12.  If it
  483.        * is, do nothing: the next code decompressed better be CLEAR
  484.        */
  485.       
  486.       FreeCode++;
  487.       if (FreeCode >= MaxCode) {
  488.     if (CodeSize < 12) {
  489.       CodeSize++;
  490.       MaxCode *= 2;
  491.       ReadMask = (1 << CodeSize) - 1;
  492.     }
  493.       }
  494.     }
  495.     Code = ReadCode();
  496.     if (npixels >= maxpixels) break;
  497.   }
  498.   free(Raster);  Raster = NULL;
  499.   
  500.   if (npixels != maxpixels) {
  501.     SetISTR(ISTR_WARNING,"This GIF file seems to be truncated.  Winging it.");
  502.     memset(pic+npixels, 0, maxpixels-npixels);  /* clear to EOBuffer */
  503.   }
  504.  
  505.   if (fp != stdin) fclose(fp);
  506.  
  507.   SetDirRButt(F_FORMAT, F_GIF);
  508.   SetDirRButt(F_COLORS, F_FULLCOLOR);
  509.  
  510.   return 0;
  511. }
  512.  
  513.  
  514. /* Fetch the next code from the raster data stream.  The codes can be
  515.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  516.  * maintain our location in the Raster array as a BIT Offset.  We compute
  517.  * the byte Offset into the raster array by dividing this by 8, pick up
  518.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  519.  * bring the desired code to the bottom, then mask it off and return it. 
  520.  */
  521.  
  522. static int ReadCode()
  523. {
  524.   int RawCode, ByteOffset;
  525.   
  526.   ByteOffset = BitOffset / 8;
  527.   RawCode = Raster[ByteOffset] + (Raster[ByteOffset + 1] << 8);
  528.   if (CodeSize >= 8)
  529.     RawCode += ( ((int) Raster[ByteOffset + 2]) << 16);
  530.   RawCode >>= (BitOffset % 8);
  531.   BitOffset += CodeSize;
  532.  
  533.   return(RawCode & ReadMask);
  534. }
  535.  
  536.  
  537. /***************************/
  538. static void DoInterlace(Index)
  539.      byte Index;
  540. {
  541.   static byte *ptr = NULL;
  542.   static int   oldYC = -1;
  543.   
  544.   if (oldYC != YC) {  ptr = pic + YC * Width;  oldYC = YC; }
  545.   
  546.   if (YC<Height)
  547.     *ptr++ = Index;
  548.   
  549.   /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  550.   
  551.   if (++XC == Width) {
  552.     
  553.     /* deal with the interlace as described in the GIF
  554.      * spec.  Put the decoded scan line out to the screen if we haven't gone
  555.      * past the bottom of it
  556.      */
  557.     
  558.     XC = 0;
  559.     
  560.     switch (Pass) {
  561.     case 0:
  562.       YC += 8;
  563.       if (YC >= Height) { Pass++; YC = 4; }
  564.       break;
  565.       
  566.     case 1:
  567.       YC += 8;
  568.       if (YC >= Height) { Pass++; YC = 2; }
  569.       break;
  570.       
  571.     case 2:
  572.       YC += 4;
  573.       if (YC >= Height) { Pass++; YC = 1; }
  574.       break;
  575.       
  576.     case 3:
  577.       YC += 2;  break;
  578.       
  579.     default:
  580.       break;
  581.     }
  582.   }
  583. }
  584.  
  585.  
  586.       
  587. /*****************************/
  588. static int GifError(st)
  589.      char *st;
  590. {
  591.   fprintf(stderr,"%s: LoadGIF() - %s\n",cmd,st);
  592.   
  593.   if (RawGIF != NULL) free(RawGIF);
  594.   if (Raster != NULL) free(Raster);
  595.   if (pic    != NULL) free(pic);
  596.   
  597.   return -1;
  598. }
  599.  
  600.